home *** CD-ROM | disk | FTP | other *** search
- From: Jeff Lee <talcott!seismo!gatech!jeff>
- Subject: Georgia Tech 'se' screen editor (Part 2 of 8)
- Keywords: Software Tools, Yet Another Screen Editor, Both BSD and USG
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 83
- Submitted by: Jeff Lee <seismo!gatech!jeff>
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # main.c
- # edit.c
- # scratch.c
- # This archive created: Tue Apr 29 11:01:33 1986
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'main.c'" '(14853 characters)'
- if test -f 'main.c'
- then
- echo shar: "will not over-write existing file 'main.c'"
- else
- cat << \SHAR_EOF > 'main.c'
- /*
- ** main.c
- **
- ** main program and lots of other routines
- ** for the se screen editor.
- */
-
- #include "se.h"
-
- /* declare global variables */
-
- /* Concerning line numbers: */
- int Line1; /* first line number on command */
- int Line2; /* second line number on command */
- int Nlines; /* number of line numbers specified */
- int Curln; /* current line; value of dot */
- int Lastln; /* last line; value of dollar */
-
-
- /* Concerning patterns: */
- char Pat[MAXPAT] = ""; /* saved pattern */
-
-
- /* Concerning the text of lines: */
- char Txt[MAXLINE]; /* text of current line */
-
-
- /* Concerning file names: */
- char Savfil[MAXLINE] = ""; /* remembered file name */
-
-
- /* Concerning line descriptors: */
- LINEDESC Buf[MAXBUF];
- #ifdef OLD_SCRATCH
- LINEDESC *Lastbf; /* last pointer used in Buf */
- LINEDESC *Free; /* head of free list */
- #endif
- LINEDESC *Line0; /* head of list of line descriptors */
-
-
- /* Concerning the 'undo' command: */
- LINEDESC *Limbo; /* head of limbo list for undo */
- int Limcnt; /* number of lines in limbo list */
-
-
- /* Concerning the scratch file: */
- filedes Scr; /* scratch file descriptor */
- unsigned Scrend; /* end of info on scratch file */
- char Scrname[MAXLINE]; /* name of scratch file */
- int Lost_lines; /* number of garbage lines in scratch file */
-
-
- /* Concerning miscellaneous variables */
- int Buffer_changed = NO;/* YES if buffer changed since last write */
- int Errcode = ENOERR; /* cause of most recent error */
- int Saverrcode = ENOERR;/* cause of previous error */
- int Probation = NO; /* YES if unsaved buffer can be destroyed */
- int Argno; /* command line argument pointer */
- char Last_char_scanned = 0; /* last char scanned w/ctl-[sl], init illegal */
- #ifdef HARD_TERMS
- int Tspeed; /* terminal speed in characters/second */
- #endif
- char Peekc = EOS; /* push a SKIP_RIGHT if adding delimiters */
- #ifdef BSD4_2
- int Reading = NO; /* are we doing terminal input? */
- #endif
-
-
- /* Concerning options: */
- int Tabstops[MAXLINE]; /* array of tab stops */
- char Unprintable = ' '; /* char to print for unprintable chars */
- int Absnos = NO; /* use absolute numbers in margin */
- int Nchoise = EOS; /* choice of line number for cont. display */
- int Overlay_col = 0; /* initial cursor column for 'v' command */
- int Warncol; /* where to turn on column warning, set in dosopt() */
- int Firstcol = 0; /* leftmost column to display */
- int Indent = 1; /* indent col; 0=same as previous line */
- int Notify = YES; /* notify user if he has mail in mail file */
- int Globals = NO; /* substitutes in a global don't fail */
- int No_hardware; /* never use hardware insert/delete */
-
-
- #ifdef HARD_TERMS
- /* Concerning the terminal type */
- int Term_type; /* terminal type */
- #endif
-
-
- /* Concerning the screen format: */
- char Screen_image[MAXROWS][MAXCOLS];
- char Msgalloc[MAXCOLS]; /* column allocation of status line */
- int Nrows; /* number of rows on screen */
- int Ncols; /* number of columns on screen */
- int Currow; /* vertical cursor coordinate */
- int Curcol; /* horizontal cursor coordinate */
- int Toprow; /* top row of window field on screen */
- int Botrow; /* bottom row of window field on screen */
- int Cmdrow; /* row number of command line */
- int Topln; /* line number of first line on screen */
- int Insert_mode; /* flag to specify character insertion */
- int Invert_case; /* flag to specify case mapping on input */
- int First_affected; /* number of first line affected by cmd */
- int Rel_a; /* char to use for first alpha line number */
- int Rel_z; /* char to use for last alpha line number */
- int Scline[MAXROWS]; /* lines currently on screen (rel to Sctop) */
- int Sctop; /* first line currently on screen */
- int Sclen; /* number of lines currently on screen */
- char Blanks[MAXCOLS]; /* all blanks for filling in lines on screen */
- char Tobuf[MAXTOBUF]; /* buffer for collecting terminal output */
- char *Tobp = Tobuf - 1; /* pointer to last used part of Tobuf */
-
-
- /* Concerning interrupts: */
- int Int_caught = 0; /* caught a SIGINT from user */
- int Hup_caught = 0; /* caught a SIGHUP when phone line dropped */
- #ifdef BSD
- int Catching_stops; /* catching or ignoring SIGTSTP's? */
- #endif
-
- /* Concerning Unix and SWT compatiblity: */
- int Unix_mode = YES; /* behaving like Unix editors? */
- char BACKSCAN = '?'; /* back scan character */
- char NOTINCCL = '^'; /* class negation character */
- char XMARK = '~'; /* global exclude on mark name */
- char ESCAPE = '\\'; /* escape character */
-
- /* Concering Georgia Tech specific code: */
- int At_gtics = NO; /* are we running at Georgia Tech ICS? */
-
- /* Concerning file encryption: */
- int Crypting = NO; /* doing file encryption? */
- char Key[KEYSIZE] = ""; /* saved encryption key */
-
-
- /* main --- main program for screen editor */
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- char *basename ();
- int int_hdlr (), hup_hdlr ();
- int (*old_int)(), (*old_quit)();
- #ifdef BSD
- int stop_hdlr (), (*old_stop)();
- #endif
- /* catch quit and hangup signals */
- /*
- * In the terminal driver munging routines, we set Control-P
- * to generate an interrupt, and turn off generating Quits from
- * the terminal. Now we just ignore them if sent from elsewhere.
- */
-
- signal (SIGHUP, hup_hdlr);
-
- old_int = signal (SIGINT, int_hdlr);
- old_quit = signal (SIGQUIT, SIG_IGN);
-
- #ifdef notdef
- /*
- * This is commented out so that se can be run from the news
- * software. Commenting it out will also allow you to put it
- * in the background, which could give you trouble. So beware.
- */
-
- if (old_int == SIG_IGN || old_quit == SIG_IGN)
- {
- /* fired off into the background, refuse to run */
- if (isatty (fileno (stdin)))
- {
- fprintf (stderr, "%s: I refuse to run in the background.\n",
- basename (argv[0]));
- exit (2);
- }
- /* else
- assume input is a script */
- }
- #endif
-
- #ifdef BSD
- old_stop = signal (SIGTSTP, stop_hdlr);
-
- if (old_stop == SIG_IGN) /* running bourne shell */
- {
- signal (SIGTSTP, SIG_IGN); /* restore it */
- Catching_stops = NO;
- }
- else
- Catching_stops = YES;
- /* running C-shell or BRL sh, catch Control-Z's */
- #endif
-
- /* set terminal to no echo, no output processing, break enabled */
- ttyedit ();
-
- #ifdef HARD_TERMS
- Tspeed = getspeed (1); /* speed of stdout */
- #endif
-
- initialize (argc, argv);
-
- edit (argc, argv);
-
- #ifndef HARD_TERMS
- t_exit ();
- #endif
-
- /* reset the terminal mode */
- ttynormal ();
- }
-
-
- #ifdef HARD_TERMS
- /* decode_mnemonic --- decode a terminal type mnemonic */
-
- int decode_mnemonic (str)
- char str[];
- {
- int i;
- int strbsr ();
-
- static struct {
- char *s;
- int t;
- } stab[] = {
- "950", TVI950,
- "adm31", ADM31,
- "adm3a", ADM3A,
- "anp", ANP,
- "b150", BEE150,
- "b200", BEE200,
- "cg", CG,
- "consul", ADDS980,
- "esprit", ESPRIT,
- "fox", FOX,
- "gt40", GT40,
- "h19", H19,
- "haz", HAZ1510,
- "hp21", HP21,
- "hz1510", HAZ1510,
- "ibm", IBM,
- "isc", ISC8001,
- "netron", NETRON,
- "regent", ADDS100,
- "regent40", ADDS100, /* kludge */
- "sbee", SBEE,
- "sol", SOL,
- "trs80", TRS80,
- "ts1", TS1,
- "tvt", TVT,
- "vc4404", VC4404,
- "vi200", VI200,
- "vi300", VI300,
- "vi50", VI50,
- };
-
- i = strbsr ((char *)stab, sizeof (stab), sizeof (stab[0]), str);
- if (i == EOF)
- return (ERR);
- else
- return (stab[i].t);
- }
- #endif
-
-
-
- /* error --- print error message and die semi-gracefully */
-
- error (msg)
- char *msg;
- {
- /*
- * You might think we want to try and save the buffer,
- * BUT, fatal errors can be caused by buffer problems,
- * which would end up putting us into a non-ending recursion.
- */
-
- ttynormal ();
- fprintf (stderr, "%s\n", msg);
- signal (SIGQUIT, SIG_DFL); /* restore normal quit handling */
- kill (getpid(), SIGQUIT); /* dump memory */
- }
-
-
- /* get_term_type --- force user to divulge terminal type */
-
- #ifndef HARD_TERMS
- get_term_type ()
- {
- int setcaps ();
- #else
- get_term_type (term_type)
- int *term_type;
- {
- int decode_mnemonic ();
- #endif
-
- char *p;
- char *getenv ();
-
- if ((p = getenv ("TERM")) == NULL)
- {
- ttynormal ();
- fprintf (stderr, "You must set your terminal type with 'TERM=<type>'\n");
- exit (1);
- }
-
- #ifdef HARD_TERMS
- if ((*term_type = decode_mnemonic()) == ERR)
- #else
- if (setcaps (p) == ERR)
- #endif
- {
- ttynormal ();
- fprintf (stderr, "I'm sorry, but I can't support %s terminals.\n", p);
- exit (1);
- }
- }
-
-
- /* initialize --- set up global data areas, get terminal type */
-
- initialize (argc, argv)
- int argc;
- char *argv[];
- {
- int i, dosopt ();
-
- #ifdef HARD_TERMS
- int strcmp ();
- int decode_mnemonic ();
- char lin[MAXLINE];
-
- /* Determine what type of terminal we're on */
- Argno = 1;
- strcpy (lin, &argv[Argno][0]);
- if (Argno < argc && lin[0] == '-' && lin[2] == EOS
- && (lin[1] == 't' || lin[1] == 'T'))
- {
- Argno = 2;
- if (Argno < argc)
- {
- strcpy (lin, argv[Argno]);
- strmap (lin, 'l');
- Term_type = decode_mnemonic (lin);
- if (Term_type == ERR)
- usage ();
- else
- Argno++;
- }
- else
- usage ();
- }
- else
- get_term_type (&Term_type);
- #else
- Argno = 1;
- get_term_type ();
- #endif
-
- /* Initialize the scratch file: */
- mkbuf ();
-
- /* Initialize screen format parameters: */
- setscreen ();
-
- /* Initialize the array of blanks to blanks */
- for (i = 0; i < Ncols; i++)
- Blanks[i] = ' ';
- Blanks[i] = '\0';
-
- if (dosopt ("") == ERR)
- error ("in initialize: can't happen");
-
- return;
- }
-
-
-
-
- /* intrpt --- see if there has been an interrupt or hangup */
-
- int intrpt ()
- {
- if (Int_caught)
- {
- Errcode = EBREAK;
- Int_caught = 0;
- return (1);
- }
- else if (Hup_caught)
- {
- Errcode = EHANGUP;
- Hup_caught = 0;
- return 1;
- }
- return (0);
- }
-
-
- /* int_hdlr --- handle an interrupt signal */
-
- int_hdlr ()
- {
- #ifndef BSD4_2
- signal (SIGINT, int_hdlr);
- #endif
- Int_caught = 1;
- }
-
- /* hup_hdlr --- handle a hangup signal */
-
- hup_hdlr ()
- {
- #ifndef BSD4_2
- signal (SIGHUP, hup_hdlr);
- Hup_caught = 1;
- #else
- /* do things different cause of 4.2 (sigh) */
- Hup_caught = 1;
- if (Reading) /* doing tty i/o, and that is where hup came from */
- hangup ();
- #endif
- }
-
- #ifdef BSD
- /* stop_hdlr --- handle the berkeley stop/suspend signal */
-
- int stop_hdlr ()
- {
- clrscreen ();
- tflush ();
- ttynormal ();
- #ifdef BSD4_2
- /* this handler remains in effect, use uncatchable signal */
- kill (getpid(), SIGSTOP);
- #else
- /* action was reset to default when we caught it */
- kill (getpid(), SIGTSTP);
- #endif
- /*
- * user does a "fg"
- */
- #ifndef BSD4_2
- signal (SIGTSTP, stop_hdlr); /* reset stop catching */
- #endif
- ttyedit ();
- restore_screen ();
- }
- #endif
-
-
- /* hangup --- dump contents of edit buffer if SIGHUP occurs */
-
- hangup ()
- {
- /* close terminal to avoid hanging on any accidental I/O: */
- close (0);
- close (1);
- close (2);
-
- signal (SIGHUP, SIG_IGN);
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
- Hup_caught = 0;
- Crypting = NO; /* force buffer to be clear text */
- dowrit (1, Lastln, "se.hangup", NO, YES, NO);
- clrbuf ();
- exit (1);
- }
-
-
- /* mswait --- message waiting subroutine */
-
- /* if the user wants to be notified, and the mail file is readable, */
- /* and there is something in it, then he is given the message. */
- /* the om command toggles Notify, controlling notification. */
-
- #include <sys/types.h>
- #include <sys/stat.h>
-
- mswait ()
- {
- int access ();
- char *getenv ();
- struct stat buf;
- static char *mbox = NULL;
- static int first = YES;
- static unsigned long mtime = 0L;
-
- if (! Notify)
- return;
-
- if (first)
- {
- first = NO;
- if ((mbox = getenv ("MAIL")) != NULL && access (mbox, 4) == 0)
- {
- if (stat (mbox, &buf) >= 0)
- {
- mtime = buf.st_mtime;
- if (buf.st_size > 0)
- remark ("You have mail");
- }
- }
- }
- else if (mbox && stat (mbox, &buf) >= 0 && buf.st_mtime > mtime)
- {
- mtime = buf.st_mtime;
- remark ("You have new mail");
- twrite (1, "\007", 1); /* Bell */
- }
- }
-
-
- /* printverboseerrormessage --- print verbose error message */
-
- printverboseerrormessage ()
- {
- switch (Errcode) {
- case EBACKWARD:
- remark ("Line numbers in backward order");
- break;
- case ENOPAT:
- remark ("No saved pattern -- sorry");
- break;
- case EBADPAT:
- remark ("Bad syntax in pattern");
- break;
- case EBADSTR:
- remark ("Bad syntax in string parameter");
- break;
- case EBADSUB:
- remark ("Bad syntax in substitution string");
- break;
- case ECANTREAD:
- remark ("File is not readable");
- break;
- case EEGARB:
- remark ("Garbage after your command");
- break;
- case EFILEN:
- remark ("Bad syntax in file name");
- break;
- case EBADTABS:
- remark ("Bad tabstop syntax");
- break;
- case EINSIDEOUT:
- remark ("Can't move a group into itself");
- break;
- case EKNOTFND:
- remark ("No line has that mark name");
- break;
- case ELINE1:
- remark ("");
- break;
- case E2LONG:
- remark ("Resultant line too long to handle");
- break;
- case ENOERR:
- remark ("No error to report");
- break;
- case ENOLIMBO:
- remark ("No lines in limbo");
- break;
- case EODLSSGTR:
- remark ("Expected '<', '>', or nothing after 'od'");
- break;
- case EORANGE:
- remark ("Line number out of range");
- break;
- case EOWHAT:
- remark ("Can't recognize option");
- break;
- case EPNOTFND:
- remark ("No line contains that pattern");
- break;
- case ESTUPID:
- remark ("Buffer hasn't been saved");
- break;
- case EWHATZAT:
- remark ("No command recognized");
- break;
- case EBREAK:
- remark ("You interrupted me");
- break;
- case ELINE2:
- remark ("Last line number beyond end of file");
- break;
- case ECANTWRITE:
- remark ("File is not writeable");
- break;
- case ECANTINJECT:
- remark ("No room for any more lines!");
- break;
- case ENOMATCH:
- remark ("No match for pattern");
- break;
- case ENOFN:
- remark ("No saved filename");
- break;
- case EBADLIST:
- remark ("Bad syntax in character list");
- break;
- case ENOLIST:
- remark ("No saved character list -- sorry");
- break;
- case ENONSENSE:
- remark ("Unreasonable value");
- break;
- case ENOHELP:
- remark ("No help available");
- break;
- case EBADLNR:
- remark ("Line numbers not allowed");
- break;
- case EFEXISTS:
- remark ("File already exists");
- break;
- case EBADCOL:
- remark ("Improper column number specification");
- break;
- case ENOLANG:
- remark ("Unknown source language");
- break;
- case ETRUNC:
- remark ("Lines were truncated");
- break;
- case ENOSHELL:
- remark ("Type control-q to rebuild screen");
- break;
- case ECANTFORK:
- remark ("Can't fork --- get help!");
- break;
- case ENOSUB:
- remark ("No saved replacement --- sorry");
- break;
- case ENOCMD:
- remark ("No saved shell command --- sorry");
- break;
- default:
- remark ("?");
- break;
- }
- Errcode = ENOERR;
- }
-
-
- /* usage --- print usage diagnostic and die */
-
- usage ()
- {
- ttynormal ();
- #ifdef HARD_TERMS
- fprintf (stderr, "Usage: se [-t <terminal>] { <pathname | -<opt> }\n");
- #else
- fprintf (stderr, "Usage: se { <pathname> | -<option> }\n");
- #endif
- exit (1);
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'edit.c'" '(27163 characters)'
- if test -f 'edit.c'
- then
- echo shar: "will not over-write existing file 'edit.c'"
- else
- cat << \SHAR_EOF > 'edit.c'
- /*
- ** edit.c
- **
- ** editor main routine, plus other routines used a lot.
- */
-
- #include "se.h"
- #include "extern.h"
-
- static char Savknm = DEFAULTNAME; /* saved mark name for < and > */
-
- /* edit --- main routine for screen editor */
-
- edit (argc, argv)
- int argc;
- char *argv[];
- {
- int cursav, status, len, cursor;
- int ckglob (), docmd (), doglob (), doread ();
- int getlst (), nextln (), prevln ();
- char lin[MAXLINE], term;
-
- watch (); /* display time of day */
-
- gatech (); /* check if running at Gatech. do magic stuff if yes */
-
- serc (); /* execute commands in $HOME/.serc file, if possible */
-
- status = OK;
-
- while (status == OK && Argno < argc)
- {
- strcpy (lin, argv[Argno]);
- loadstr (lin, Argno, POOPCOL, Ncols);
- if (lin[0] == '-')
- {
- len = strlen (lin) + 1;
- lin[len - 1] = '\n';
- lin[len] = EOS;
- len = 0;
- status = doopt (lin, &len);
- }
- else
- {
- dfltsopt (lin);
- status = doread (Lastln, lin, NO);
- }
- Argno++;
- }
-
- if (status == ERR)
- {
- if (Errcode == EHANGUP)
- hangup ();
- printverboseerrormessage ();
- }
- else
- Curln = min (1, Lastln);
-
- Buffer_changed = NO;
- First_affected = 1; /* maintained by updscreen & commands */
- updscreen ();
-
- if (status != ERR) /* leave offending file name or option */
- lin[0] = EOS;
- cursor = 0;
-
- /* main command loop */
- do {
- intrpt (); /* discard pending breaks (interrupts) */
- if (Lost_lines > GARB_THRESHOLD
- && (Lastln + Limcnt) / Lost_lines <= GARB_FACTOR)
- garbage_collect ();
-
- mswait (); /* check for pending messages */
- Cmdrow = Botrow + 1; /* reset the command line location */
- prompt ("cmd>");
- getcmd (lin, 0, &cursor, &term);
- remark (""); /* clear out any error messages */
-
- while (term == CURSOR_UP || term == CURSOR_DOWN
- || term == CURSOR_SAME)
- {
- switch (term) {
- case CURSOR_UP:
- if (Curln > 1)
- Curln--;
- else
- Curln = Lastln;
- break;
-
- case CURSOR_DOWN:
- if (Curln < Lastln)
- Curln++;
- else
- Curln = min (1, Lastln);
- break;
- }
- adjust_window (Curln, Curln);
- updscreen ();
- getcmd (lin, 0, &cursor, &term);
- }
-
- prompt (""); /* remove prompt */
-
- cursav = Curln; /* remember it in case of an error */
- Errcode = EEGARB; /* default error code for garbage at end */
-
- len = 0;
- if (getlst (lin, &len, &status) == OK)
- {
- if (ckglob (lin, &len, &status) == OK)
- doglob (lin, &len, &cursav, &status);
- else if (status != ERR)
- docmd (lin, len, NO, &status);
- }
- if (status == ERR)
- {
- if (Errcode == EHANGUP)
- hangup ();
- printverboseerrormessage ();
- Curln = min (cursav, Lastln);
- }
- else if (term != FUNNY)
- {
- cursor = 0;
- lin[0] = EOS;
- }
-
- adjust_window (Curln, Curln);
- updscreen ();
-
- } while (status != EOF);
-
- clrscreen ();
- clrbuf ();
- tflush ();
-
- return;
- }
-
-
- /* getlst --- collect line numbers (if any) at lin[*i], increment i */
-
- int getlst (lin, i, status)
- char lin[];
- int *i, *status;
- {
- int num;
- int getone ();
-
- Line2 = 0;
- for (Nlines = 0; getone (lin, i, &num, status) == OK; )
- {
- Line1 = Line2;
- Line2 = num;
- Nlines++;
- if (lin[*i] != ',' && lin[*i] != ';')
- break;
- if (lin[*i] == ';')
- Curln = num;
- (*i)++;
- }
-
- if (Nlines > 2)
- Nlines = 2;
-
- if (Nlines <= 1)
- Line1 = Line2;
-
- if (Line1 > Line2)
- {
- *status = ERR;
- Errcode = EBACKWARD;
- }
-
- if (*status != ERR)
- *status = OK;
-
- return (*status);
- }
-
-
- /* getnum --- convert one term to line number */
-
- int getnum (lin, i, pnum, status)
- char lin[];
- register int *i, *pnum, *status;
- {
- int j, ret;
- int ctoi (), optpat (), ptscan (), knscan (), getkn ();
- int k;
-
- ret = OK;
- SKIPBL (lin, *i);
- if (lin[*i] >= Rel_a && lin[*i] <= Rel_z && Absnos == NO)
- *pnum = Topln - Toprow + lin[*i] - Rel_a;
- else if (lin[*i] == CURLINE)
- *pnum = Curln;
- else if (lin[*i] == PREVLINE || lin[*i] == PREVLINE2)
- *pnum = Curln - 1;
- else if (lin[*i] == LASTLINE)
- *pnum = Lastln;
- else if (lin[*i] == SCAN || lin[*i] == BACKSCAN)
- {
- int missing_delim = YES;
-
- /* see if trailing delim supplied, since command can follow pattern */
- for (k = *i + 1; lin[k] != EOS; k++)
- if (lin[k] == ESCAPE)
- k++; /* skip esc, loop will skip escaped char */
- else if (lin[k] == lin[*i])
- {
- missing_delim = NO;
- break;
- }
- /* else
- continue */
-
- if (missing_delim == YES)
- {
- for (; lin[k] != EOS; k++)
- ;
- k--; /* k now at newline */
-
- /* supply trailing delim */
- lin[k] = lin[*i];
- lin[++k] = '\n';
- lin[++k] = EOS;
- Peekc = SKIP_RIGHT;
- }
-
- if (optpat (lin, i) == ERR)
- ret = ERR;
- else if (lin[*i] == SCAN)
- ret = ptscan (FORWARD, pnum);
- else
- ret = ptscan (BACKWARD, pnum);
- }
- else if (lin[*i] == SEARCH || lin[*i] == BACKSEARCH)
- {
- j = *i;
- (*i)++;
- if (getkn (lin, i, &Savknm, Savknm) == ERR)
- ret = ERR;
- else if (lin[j] == SEARCH)
- ret = knscan (FORWARD, pnum);
- else
- ret = knscan (BACKWARD, pnum);
- (*i)--;
- }
- else if (isdigit (lin[*i]))
- {
- *pnum = ctoi (lin, i);
- (*i)--;
- }
- else if (lin[*i] == TOPLINE)
- *pnum = Topln;
- else
- ret = EOF;
-
- if (ret == OK)
- (*i)++;
- *status = ret;
- return (ret);
- }
-
-
- /* getone --- evaluate one line number expression */
-
- int getone (lin, i, num, status)
- char lin[];
- register int *i, *num, *status;
- {
- int pnum, ret;
- int getnum ();
- char porm; /* "plus or minus" (sic) */
-
- ret = EOF; /* assume we won't find anything for now */
- *num = 0;
-
- if (getnum (lin, i, num, status) == OK) /* first term */
- {
- ret = OK; /* to indicate we've seen something */
- do { /* + or - terms */
- porm = EOS;
- SKIPBL (lin, *i);
- if (lin[*i] == '-' || lin[*i] == '+')
- {
- porm = lin[*i];
- (*i)++;
- }
- if (getnum (lin, i, &pnum, status) == OK)
- if (porm == '-')
- *num -= pnum;
- else
- *num += pnum;
- if (*status == EOF && porm != EOS) /* trailing + or - */
- *status = ERR;
- } while (*status == OK);
- }
-
- if (*num < 0 || *num > Lastln) /* make sure number is in range */
- {
- *status = ERR;
- Errcode = EORANGE;
- }
-
- if (*status == ERR)
- ret = ERR;
- else
- *status = ret;
-
- return (ret);
- }
-
-
- #ifndef OLD_SCRATCH
- #ifndef OLD_GLOB
- static int special_casing = NO;
- #endif
- #endif
-
- /* ckglob --- if global prefix, mark lines to be affected */
-
- int ckglob (lin, i, status)
- char lin[];
- int *i, *status;
- {
- register int line, tmp;
- int usepat, usemark;
- int defalt (), match (), optpat (), getkn ();
- register LINEDESC *k;
- LINEDESC *gettxt (), *getind ();
- #ifndef OLD_SCRATCH
- #ifndef OLD_GLOB
- char start_line = Unix_mode ? '^' : '%';
- #endif
- #endif
-
- *status = OK;
- usepat = EOF;
- usemark = EOF;
-
- #ifndef OLD_SCRATCH
- #ifndef OLD_GLOB
- if ( /* g/^/m0 or g/$/m0 -- special case the pathological */
- /* cases in order to save time */
- (lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
- && (lin[*i + 1] == lin[*i + 3])
- && (lin[*i + 2] == start_line || lin[*i + 2] == '$')
- && (lin[*i + 4] == MOVECOM || lin[*i + 4] == UCMOVECOM)
- && (lin[*i + 5] == '0' && lin[*i + 6] == '\n') )
- {
- special_casing = YES;
- remark ("GLOB");
- return (OK);
- }
- #endif
- #endif
- if (lin[*i] == GMARK || lin[*i] == XMARK) /* global markname prefix? */
- {
- if (lin[*i] == GMARK) /* tag lines with the specified markname */
- usemark = YES;
- else /* tag lines without the specified markname */
- usemark = NO;
- (*i)++;
- *status = getkn (lin, i, &Savknm, Savknm);
- }
-
- if (*status == OK) /* check for a pattern prefix too */
- {
- if (lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
- usepat = YES;
-
- if (lin[*i] == EXCLUDE || lin[*i] == UCEXCLUDE)
- usepat = NO;
-
- if (usepat != EOF)
- {
- (*i)++;
- if (optpat (lin, i) == ERR)
- *status = ERR;
- else
- (*i)++;
- }
- }
-
- if (*status == OK && usepat == EOF && usemark == EOF)
- *status = EOF;
- else if (*status == OK)
- defalt (1, Lastln);
-
- if (*status == OK) /* no errors so far, safe to proceed */
- {
- remark ("GLOB");
-
- k = Line0; /* unmark all lines preceeding range */
- for (line = 0; line < Line1; line++)
- {
- k -> Globmark = NO;
- k = NEXTLINE(k);
- }
-
- for (; line <= Line2; line++) /* mark lines in range */
- {
- if (intrpt ())
- {
- *status = ERR;
- return (*status);
- }
- tmp = NO;
- if (usemark == EOF
- || usemark == YES && k -> Markname == Savknm
- || usemark == NO && k -> Markname != Savknm)
- {
- if (usepat == EOF) /* no global pattern to look for */
- tmp = YES;
- else /* there is also a pattern to look for */
- {
- gtxt (k);
- if (match (Txt, Pat) == usepat)
- tmp = YES;
- }
- }
-
- k -> Globmark = tmp;
-
- k = NEXTLINE(k);
- }
-
- #ifdef OLD_SCRATCH
- /* mark remaining lines */
- for (; k != Line0; k = k -> Nextline)
- k -> Globmark = NO;
- #else
- /* mark remaining lines */
- for (; line <= Lastln; line++)
- {
- k -> Globmark = NO;
- k = NEXTLINE (k);
- }
- #endif
-
- remark ("");
- }
-
- return (*status);
- }
-
-
- /* doglob --- do command at lin[i] on all marked lines */
-
- int doglob (lin, i, cursav, status)
- char lin[];
- int *i, *cursav, *status;
- {
- register int istart, line;
- int docmd (), getlst (), nextln ();
- register LINEDESC *k;
- LINEDESC *getind ();
-
- #ifndef OLD_SCRATCH
- #ifndef OLD_GLOB
- if (special_casing)
- {
- /*
- remark ("Warp 7, Captain!");
- */
- /* not on the screen too long anyway */
- reverse (1, Lastln);
- Curln = Lastln;
- special_casing = NO;
- Buffer_changed = YES;
- First_affected = min (1, First_affected);
- remark ("");
- adjust_window (Curln, Curln);
- updscreen ();
- return (OK);
- }
- #endif
- #endif
- *status = OK;
- istart = *i;
- k = Line0;
- line = 0;
-
- do {
- line++;
- k = NEXTLINE(k);
- if (k -> Globmark == YES) /* line is marked */
- {
- k -> Globmark = NO; /* unmark the line */
- Curln = line;
- *cursav = Curln; /* remember where we are */
- *i = istart;
- if (getlst (lin, i, status) == OK)
- docmd (lin, *i, YES, status);
- line = 0; /* lines may have been moved */
- k = Line0;
- }
- if (intrpt ())
- *status = ERR;
- } while (line <= Lastln && *status == OK);
-
- return (*status);
- }
-
-
- /* ckchar --- look for ch or altch on lin at i, set flag if found */
-
- int ckchar (ch, altch, lin, i, flag, status)
- char ch, altch, lin[];
- int *i, *flag, *status;
- {
-
- if (lin[*i] == ch || lin[*i] == altch)
- {
- (*i)++;
- *flag = YES;
- }
- else
- *flag = NO;
-
- *status = OK;
- return (OK);
- }
-
-
- /* ckp --- check for "p" after command */
-
- int ckp (lin, i, pflag, status)
- char lin[];
- int i, *pflag, *status;
- {
-
- if (lin[i] == PRINT || lin[i] == UCPRINT)
- {
- i++;
- *pflag = YES;
- }
- else
- *pflag = NO;
-
- if (lin[i] == '\n')
- *status = OK;
- else
- *status = ERR;
-
- return (*status);
- }
-
-
- /* ckupd --- make sure it is ok to destroy the buffer */
-
- int ckupd (lin, i, cmd, status)
- char lin[], cmd;
- int *i, *status;
- {
- int flag;
- int ckchar ();
-
- *status = ckchar (ANYWAY, ANYWAY, lin, i, &flag, status);
- if (flag == NO && Buffer_changed == YES && Probation != cmd)
- {
- *status = ERR;
- Errcode = ESTUPID;
- Probation = cmd; /* if same command is repeated, */
- } /* we'll keep quiet */
-
- return (*status);
- }
-
-
- /* defalt --- set defaulted line numbers */
-
- defalt (def1, def2)
- int def1, def2;
- {
-
- if (Nlines == 0) /* no line numbers supplied, use defaults */
- {
- Line1 = def1;
- Line2 = def2;
- }
-
- return;
- }
-
-
- /* getfn --- get file name from lin[i]... */
-
- int getfn (lin, i, file)
- char lin[], file[];
- int i;
- {
- int j, k, ret;
-
- ret = ERR;
- if (lin[i + 1] == ' ')
- {
- j = i + 2; /* get new file name */
- SKIPBL (lin, j);
- for (k = 0; lin[j] != NEWLINE; k++, j++)
- file[k] = lin[j];
- file[k] = EOS;
- if (k > 0)
- ret = OK;
- }
- else if (lin[i + 1] == '\n' && Savfil[0] != EOS)
- {
- strcpy (file, Savfil); /* or old name */
- ret = OK;
- }
- else
- if (lin[i + 1] == '\n')
- Errcode = ENOFN;
- else
- Errcode = EFILEN;
-
- if (ret == OK && Savfil[1] == EOS)
- {
- strcpy (Savfil, file); /* save if no old one */
- mesg (Savfil, FILE_MSG);
- }
-
- return (ret);
- }
-
-
- /* getkn --- get mark name from lin[i], increment i */
-
- int getkn (lin, i, kname, dfltnm)
- char lin[], *kname, dfltnm;
- int *i;
- {
-
- if (lin[*i] == '\n' || lin[*i] == EOS)
- {
- *kname = dfltnm;
- return (EOF);
- }
-
- *kname = lin[*i];
- (*i)++;
- return (OK);
- }
-
-
- /* getrange --- get 'from' range for tlit command */
-
- int getrange (array, k, set, size, allbut)
- char array[], set[];
- int *k, size, *allbut;
- {
- int i, j;
- int addset ();
-
- Errcode = EBADLIST; /* preset error code */
-
- i = *k + 1;
- if (array[i] == NOTINCCL) /* check for negated character class */
- {
- *allbut = YES;
- i++;
- }
- else
- *allbut = NO;
-
- j = 0;
- filset (array[*k], array, &i, set, &j, size);
- if (array[i] != array[*k])
- {
- set[0] = EOS;
- return (ERR);
- }
- if (set[0] == EOS)
- {
- Errcode = ENOLIST;
- return (ERR);
- }
- if (j > 0 && addset (EOS, set, &j, size) == NO)
- {
- set[0] = EOS;
- return (ERR);
- }
-
- *k = i;
- Errcode = EEGARB;
-
- return (OK);
- }
-
-
- /* getrhs --- get substitution string for 's' command */
-
- int getrhs (lin, i, sub, gflag)
- char lin[], sub[];
- int *i, *gflag;
- {
- static char Subs[MAXPAT] = ""; /* saved replacement pattern */
- int j, maksub ();
- char saved_sub = Unix_mode ? '%' : '&';
- /* saved replacement pattern char */
-
-
- Errcode = EBADSUB;
-
- if (lin[*i] == EOS) /* missing the middle delimeter */
- return (ERR);
-
- if (lin[*i + 1] == saved_sub && (lin[*i + 2] == lin[*i]
- || lin[*i + 2] == '\n'))
- {
- /*
- * s//%/ --- should mean do the same thing as I did last time, even
- * s//&/ --- if I deleted something. So we comment out these lines.
- *
- if (Subs[0] == EOS)
- {
- Errcode = ENOSUB;
- return (ERR);
- }
- */
- strcpy (sub, Subs);
- *i += 2;
- if (lin[*i] == '\n')
- {
- /* fix it up for pattern matching routines */
- lin[*i] = lin[*i - 2];
- lin[*i + 1] = '\n';
- lin[*i + 2] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else /* not using saved substitution pattern */
- {
- if (lin[*i + 1] == '\n')
- {
- /* missing the trailing delimiter */
- /* pattern was empty */
- lin[*i + 1] = lin[*i]; /* supply missing delimiter */
- lin[*i + 2] = '\n';
- lin[*i + 3] = EOS;
- Peekc = SKIP_RIGHT;
- /* return (ERR); /* this is the original action */
- }
- else
- {
- /* stuff in pattern, check end of line */
- for (j = *i; lin[j] != EOS; j++)
- ;
- j -= 2; /* j now points to char before '\n' */
-
- if (lin[j] == 'p' || lin[j] == 'P')
- {
- --j;
- if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
- {
- if (j >= *i + 1 && lin[j-1] == lin[*i]
- && (lin[j-2] != ESCAPE
- || lin[j-3] == ESCAPE))
- ; /* leave alone */
- else
- {
- /* \<delim>gp\n is pattern */
- /* supply trailing delim */
- j += 2; /* j at \n */
- lin[j] = lin[*i];
- lin[++j] = '\n';
- lin[++j] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else if (j >= *i + 1 && lin[j] == lin[*i] &&
- (lin[j-1] != ESCAPE
- || lin[j-2] == ESCAPE))
- ; /* leave alone */
- else
- {
- /* \<delim>p\n is pattern */
- /* supply trailing delim */
- j += 2;
- lin[j] = lin[*i];
- lin[++j] = '\n';
- lin[++j] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
- {
- --j;
- if (j >= *i + 1 && lin[j] == lin[*i] &&
- (lin[j-1] != ESCAPE
- || lin[j-2] == ESCAPE))
- ; /* leave alone */
- else
- {
- /* \<delim>g\n is pattern */
- /* supply trailing delim */
- j += 2; /* j at \n */
- lin[j] = lin[*i];
- lin[++j] = '\n';
- lin[++j] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else if ((lin[j] != lin[*i]) ||
- (lin[j] == lin[*i] &&
- lin[j-1] == ESCAPE && lin[j-2] != ESCAPE))
- {
- /* simply missing trailing delimeter */
- /* supply it */
- j++; /* j at \n */
- lin[j] = lin[*i];
- lin[++j] = '\n';
- lin[++j] = EOS;
- Peekc = SKIP_RIGHT;
- }
- /* else
- unescaped delim is there,
- leave well enough alone */
- }
-
- if ((*i = maksub (lin, *i + 1, lin[*i], sub)) == ERR)
- return (ERR);
-
- strcpy (Subs, sub); /* save pattern for later */
- }
-
- if (lin[*i + 1] == GLOBAL || lin[*i + 1] == UCGLOBAL)
- {
- (*i)++;
- *gflag = YES;
- }
- else
- *gflag = NO;
-
- Errcode = EEGARB; /* the default */
-
- return (OK);
-
- }
-
-
- /* getstr --- get string from lin at i, copy to dst, bump i */
-
- /*
- ** NOTE: this routine only called for doing the join command.
- ** therefore, don't do anything else with it.
- */
-
- int getstr (lin, i, dst, maxdst)
- char lin[], dst[];
- int *i, maxdst;
- {
- char delim;
- char esc ();
- int j, k, d;
-
- j = *i;
- Errcode = EBADSTR;
-
- delim = lin[j];
-
- if (delim == '\n')
- {
- lin[j] = '/';
- lin[++j] = ' '; /* join with a single blank */
- lin[++j] = '/';
- lin[++j] = '\n';
- lin[++j] = EOS;
- j = *i;
- delim = lin[j];
- Peekc = SKIP_RIGHT;
- /* now fall thru */
-
- /* return (ERR); /* old way */
- }
- else if ((delim == 'p' || delim == 'P') && lin[j + 1] == '\n') /* jp */
- {
- lin[j] = '/';
- lin[++j] = ' '; /* join with a single blank */
- lin[++j] = '/';
- lin[++j] = delim; /* 'p' or 'P' */
- lin[++j] = '\n';
- lin[++j] = EOS;
- j = *i;
- delim = lin[j];
- Peekc = SKIP_RIGHT;
- /* now fall thru */
- }
-
- if (lin[j + 1] == '\n') /* command was 'j/' */
- {
- dst[0] = EOS;
- Errcode = ENOERR;
- return (OK);
- /* return (ERR); /* old way */
- }
-
- /*
- * otherwise, stuff there in the string, try to allow for
- * a missing final delimiter.
- */
-
- for (k = j + 1; lin[k] != '\n'; k++)
- ; /* find end */
-
- k--; /* now points to char before newline */
-
- if (lin[k] == 'p' || lin[k] == 'P')
- {
- k--;
- if (lin[k] == delim &&
- (lin[k-1] != ESCAPE || lin[k-2] == ESCAPE))
- ; /* it's fine, leave it alone */
- else
- {
- /* ESCAPE delim p NEWLINE is the join string */
- /* supply trailing delimiter. */
- k += 2;
- lin[k] = delim;
- lin[++k] = '\n';
- lin[++k] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else if (lin[k] != delim || (lin[k-1] == ESCAPE && lin[k-2] != ESCAPE))
- {
- /* no delim and no p, or last char is escaped delim */
- k++;
- lin[k] = delim;
- lin[++k] = '\n';
- lin[++k] = EOS;
- Peekc = SKIP_RIGHT;
- }
- /* else
- delim is there
- leave well enough alone */
-
- /* code to actually do the join */
-
- for (k = j + 1; lin[k] != delim; k++) /* find end */
- {
- if (lin[k] == '\n' || lin[k] == EOS)
- if (delim == ' ')
- break;
- else
- return (ERR);
- esc (lin, &k);
- }
- if (k - j > maxdst)
- return (ERR);
-
- for (d = 0, j++; j < k; d++, j++)
- dst[d] = esc (lin, &j);
- dst[d] = EOS;
-
- *i = j;
- Errcode = EEGARB; /* the default */
-
- return (OK);
- }
-
-
- /* getwrd --- get next word from line at i; increment i */
-
- int getwrd (line, i, word, size)
- char line[], word[];
- int *i, size;
- {
- int j;
-
- SKIPBL (line, *i);
- j = 0;
- while (line[*i] != ' ' && line[*i] != '\n' && line[*i] != EOS)
- {
- if (j < size - 1)
- {
- word[j] = line[*i];
- j++;
- }
- (*i)++;
- }
- word[j] = EOS;
-
- return (j);
- }
-
-
- /* knscan --- scan for a line with a given mark name */
-
- int knscan (way, num)
- int way, *num;
- {
- int nextln ();
- LINEDESC *k;
- LINEDESC *getind ();
-
- *num = Curln;
- k = getind (*num);
- do {
- bump (num, &k, way);
- if (k -> Markname == Savknm)
- return (OK);
- } while (*num != Curln && ! intrpt ());
-
- if (Errcode = EEGARB)
- Errcode = EKNOTFND;
- return (ERR);
-
- }
-
-
- /* makset --- make set from array[k] in set */
-
- int makset (array, k, set, size)
- char array[], set[];
- int *k, size;
- {
- static char Tset[MAXPAT] = ""; /* saved translit dest range */
- int i, j;
- int l;
- int addset ();
- char saved_sub = Unix_mode ? '%' : '&';
-
- Errcode = EBADLIST;
-
- /*
- * try to allow missing delimiter for translit command.
- */
-
- if (array[*k] == EOS)
- return (ERR);
-
- if (array[*k + 1] == saved_sub && (array[*k + 2] == array[*k]
- || array[*k + 2] == '\n'))
- {
- strcpy (set, Tset);
- *k += 2;
- if (array[*k] == '\n')
- {
- /* fix it up for rest of the routines */
- array[*k] = array[*k - 2];
- array[*k+ 1] = '\n';
- array[*k+ 2] = EOS;
- }
- Peekc = SKIP_RIGHT;
- }
- else
- {
-
- for (l = *k; array[l] != EOS; l++)
- ;
- l -= 2; /* l now points to char before '\n' */
-
- if (l == *k) /* "y/.../\n" */
- {
- array[*k + 1] = array[*k]; /* add delimiter */
- array[*k + 2] = '\n';
- array[*k + 3] = EOS;
- Peekc = SKIP_RIGHT;
- }
- else if (array[l] == 'p' || array[l] == 'P')
- {
- --l;
- if (l >= *k + 1 && array[l] == array[*k] &&
- (array[l-1] != ESCAPE || array[l-2] == ESCAPE))
- ; /* leave alone */
- else
- {
- /* \<delim>p\n is set */
- /* supply trailing delim */
- l += 2;
- array[l] = array[*k];
- array[++l] = '\n';
- array[++l] = EOS;
- Peekc = SKIP_RIGHT;
- }
- }
- else if (array[l] != array[*k] /* no delim, and no p */
- || (array[l-1] == ESCAPE /* or last char is escaped delim */
- && array[l-2] != ESCAPE))
- {
- /* simply missing trailing delimeter */
- /* supply it */
- l++; /* l now at \n */
- array[l] = array[*k];
- array[++l] = '\n';
- array[++l] = EOS;
- Peekc = SKIP_RIGHT;
- }
- /* else
- delim is there,
- leave well enough alone */
-
- j = 0;
- i = *k + 1;
- filset (array[*k], array, &i, set, &j, size);
-
- if (array[i] != array[*k])
- return (ERR);
-
- if (addset (EOS, set, &j, size) == NO)
- return (ERR);
-
- strcpy (Tset, set); /* save for later */
- *k = i;
-
- }
-
- Errcode = EEGARB;
-
- return (OK);
- }
-
-
- /* optpat --- make pattern specified at lin[i] */
-
- int optpat (lin, i)
- char lin[];
- int *i;
- {
- int makpat ();
-
- if (lin[*i] == EOS)
- *i = ERR;
- else if (lin[*i + 1] == EOS)
- *i = ERR;
- else if (lin[*i + 1] == lin[*i]) /* repeated delimiter */
- (*i)++; /* leave existing pattern alone */
- else
- *i = makpat (lin, *i + 1, lin[*i], Pat);
-
- if (Pat [0] == EOS)
- {
- Errcode = ENOPAT;
- return (ERR);
- }
- if (*i == ERR)
- {
- Pat[0] = EOS;
- Errcode = EBADPAT;
- return (ERR);
- }
- return (OK);
- }
-
-
- /* ptscan --- scan for next occurrence of pattern */
-
- int ptscan (way, num)
- int way, *num;
- {
- LINEDESC *getind ();
- LINEDESC *k;
- int match ();
-
- *num = Curln;
- k = getind (*num);
- do {
- bump (num, &k, way);
- gtxt (k);
- if (match (Txt, Pat) == YES)
- return (OK);
- } while (*num != Curln && ! intrpt ());
-
- if (Errcode == EEGARB)
- Errcode = EPNOTFND;
-
- return (ERR);
- }
-
-
- /* settab --- set tab stops */
-
- int settab (str)
- char str[];
- {
- int i, j, n, maxstop, last, inc, ret;
- int ctoi ();
-
- for (i = 0; i < MAXLINE; i++) /* clear all tab stops */
- Tabstops[i] = NO;
-
- ret = OK;
- maxstop = 0;
- last = 1;
-
- i = 0;
- SKIPBL (str, i);
- while (str[i] != EOS && str[i] != '\n')
- {
- if (str[i] == '+') /* increment */
- {
- i++;
- inc = YES;
- }
- else
- inc = NO;
-
- n = ctoi (str, &i);
-
- if (n <= 0 || n >= MAXLINE)
- {
- ret = ERR;
- Errcode = ENONSENSE;
- break;
- }
-
- if (str[i] != ' ' && str[i] != '+' &&
- str[i] != '\n' && str[i] != EOS)
- {
- ret = ERR;
- Errcode = EBADTABS;
- break;
- }
-
- if (inc == YES)
- {
- for (j = last + n; j < MAXLINE; j += n)
- {
- Tabstops[j - 1] = YES;
- maxstop = max (j, maxstop);
- }
- }
- else
- {
- Tabstops[n - 1] = YES;
- last = n;
- maxstop = max (n, maxstop);
- }
- SKIPBL (str, i);
- } /* while ... */
-
- if (ret == ERR)
- maxstop = 0;
-
- if (maxstop == 0) /* no tab stops specified, use defaults */
- {
- for (i = 4; i < MAXLINE - 1; i += 4)
- Tabstops[i] = YES;
- maxstop = i - 4 + 1;
- }
-
- Tabstops[0] = YES; /* always set to YES */
-
- for (i = maxstop; i < MAXLINE; i++)
- Tabstops[i] = YES;
-
- return (ret);
- }
-
- /* gatech --- see if se is running at Ga. Tech. */
-
- /*
- ** if se is running at gatech, for the sake of naive users,
- ** come up in SWT compatibility mode. Personally, I would
- ** rather not do this, but, the sophisticated users can use
- ** a .serc file to turn on unix compatibility. If not at
- ** gatech, default behaviour is Unix compatibility.....
- **
- ** set the global flag, so that we can do some neat stuff in do_shell()
- */
-
- static gatech ()
- {
- int len;
- int i;
- extern char *sysname (); /* will tell us where we are */
-
- /* add system names here as Gatech gets more UNIX machines */
- /* the names MUST be in sorted order */
- /* also include the stupid gt-* names */
- static char *stab[] = {
- "cirrus",
- "gatech",
- "gt-cirrus",
- "gt-nimbus",
- "gt-stratus",
- "nimbus",
- "stratus"
- };
-
- i = strbsr ((char *) stab, sizeof (stab), sizeof (stab[0]), sysname());
-
- if (i != EOF)
- {
- len = 0;
- doopt ("ops\n", &len); /* turn on SWT compatibility */
- /* will put 'SWT' in status line */
- At_gtics = YES;
- #ifdef LOG_USAGE
- log (); /* log se usage statistics */
- #endif
- }
- else
- {
- mesg ("UNIX", MODE_MSG);
- At_gtics = NO;
- }
- }
-
- /* serc --- read in $HOME/.serc and execute the commands in it, if possible. */
-
- /*
- * note that se's special control characters are NOT processed,
- * and therefore should NOT be used in one's .serc file.
- */
-
- static serc ()
- {
- char file[MAXLINE];
- char lin[MAXLINE];
- char *expand_env ();
- FILE *fp;
- int status = ENOERR;
- int len, cursav;
-
- strcpy (file, expand_env ("$HOME/.serc"));
-
- if ((fp = fopen (file, "r")) == NULL)
- return;
-
- while (fgets (lin, sizeof lin, fp) != NULL && status != EOF /*??*/)
- {
- if (lin[0] == '#' || lin[0] == '\n')
- continue; /* comment in .serc file */
-
- /* most of this code stolen from edit() */
- len = 0;
- cursav = Curln;
- if (getlst (lin, &len, &status) == OK)
- {
- if (ckglob (lin, &len, &status) == OK)
- doglob (lin, &len, &cursav, &status);
- else if (status != ERR)
- docmd (lin, len, NO, &status);
- }
- if (status == ERR)
- {
- if (Errcode == EHANGUP)
- hangup ();
- Curln = min (cursav, Lastln);
- }
- }
- fclose (fp);
- }
-
- #ifdef LOG_USAGE
-
- /* log -- log se usage, iff at Georgia Tech */
-
-
- static log ()
- {
- static char logfile[] = "/usr/tmp/se.log"; /* a public file */
- char logname[MAXLINE], tod[26]; /* tod => time of day */
- long clock;
- FILE *fp;
- char *ctime ();
- long time ();
- int old_umask;
- #ifdef BSD
- char *getlogin ();
- #else
- char *cuserid ();
- #endif
-
- if (! At_gtics)
- return;
-
- /* get the login name */
- #ifdef BSD
- strcpy (logname, getlogin ());
- #else
- cuserid (logname);
- #endif
-
- time (&clock);
- strcpy (tod, ctime (&clock)); /* see the manual on ctime(3C) */
- tod[24] = EOS; /* delete the '\n' at the end */
-
- old_umask = umask (0); /* allow writes for everyone */
- /* when first call creates the file */
-
- if ((fp = fopen (logfile, "a")) != NULL)
- {
- /* all ok, write out statistics */
- fprintf (fp, "%s used se on %s.\n", logname, tod);
- fclose (fp);
- }
- /* else
- don't do anything */
-
- umask (old_umask);
-
- }
- #endif
-
- /* sysname --- return a string telling us who we are */
-
- #ifdef USG
- #include <sys/utsname.h> /* stuff to find out who we are */
- #endif
-
- char *sysname ()
- {
- int i, j, k;
- char c;
- static char buf[MAXLINE] = "";
- FILE *fp;
-
- #ifdef USG /* System V */
- static struct utsname whoarewe;
-
- uname (& whoarewe);
- return (whoarewe.sysname);
- #else
- #ifdef BSD4_2 /* Berkeley 4.2 */
- if (buf[0] != EOS)
- return (buf);
-
- j = sizeof (buf);
- k = gethostname (buf, & j);
- if (k != 0)
- return ("unknown");
- else
- return (buf);
- #else /* Berkeley 4.1 */
- if (buf[0] != EOS)
- return (buf);
-
- if ((fp = fopen ("/usr/include/whoami.h", "r")) == NULL)
- return ("unknown");
- else
- {
- auto char *cp;
- /*
- * file should contain a single line:
- * #define sysname "......"
- */
- while ((c = getc (fp)) != '"' && c != EOF)
- ;
- if (c == EOF)
- cp = "unknown";
- else
- {
- for (i = 0; (c = getc (fp)) != '"' && c != EOF; i++)
- buf[i] = c;
- buf[i] = EOS;
- if (c == EOF && i == 0)
- cp = "unknown";
- else
- cp = buf;
- }
- fclose (fp);
- return (cp);
- }
- #endif
- #endif
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'scratch.c'" '(11282 characters)'
- if test -f 'scratch.c'
- then
- echo shar: "will not over-write existing file 'scratch.c'"
- else
- cat << \SHAR_EOF > 'scratch.c'
- /*
- ** scratch.c
- **
- ** scratch file handling for se screen editor.
- **
- ** If OLD_SCRATCH is defined, then this file will contain the
- ** original scratch file handling, based on linked lists,
- ** from the ratfor version of Software Tools. This method is
- ** real good at moving lines around, but is poor for finding lines.
- **
- ** If OLD_SCRATCH is not defined, which is the default, this file will use
- ** the line handling methodology presented in Software Tools In Pascal,
- ** *without* changing the way any of the routines are called.
- **
- ** Bascially, the lines are always kept in order in the Buf array.
- ** Thus, lines 1 through 5 are in Buf[1] through Buf[5]. blkmove() and
- ** reverse() do the work of moving lines around in the buffer. The alloc()
- ** routine, therefore, always allocates the first empty slot, which will be
- ** at Lastln + 1, if there is room.
- **
- ** Deleted lines are kept at the end of the buffer. Limbo points to the first
- ** line in the group of lines which were last deleted, or else Limbo == NOMORE.
- **
- ** It is a very good idea to read the chapters on editing in BOTH editions of
- ** Software Tools, before trying to muck with this. It also helps to be a
- ** little bit off the wall....
- **
- ** In fact, I would go as far as saying, "If you touch this, it will break.
- ** It is held together with chewing gum, scotch tape, and bobby pins."
- ** (Of course, you could always use OLD_SCRATCH, which definitely works.
- ** It just increases the size of the editor.) So much for the old
- ** "Just replace the implementation of the underlying primitives..."
- */
-
- #include "se.h"
- #include "extern.h"
-
- /* alloc --- allocate space for a new pointer block */
-
-
- static LINEDESC *alloc (ptr)
- register LINEDESC **ptr;
- {
- #ifdef OLD_SCRATCH /* old way */
- if (Free == NOMORE) /* no free list, expand into unallocated space */
- {
- if (Lastbf - Buf + BUFENT <= MAXBUF) /* see if there's room */
- {
- *ptr = Lastbf;
- Lastbf += BUFENT;
- }
- else
- *ptr = NOMORE; /* out of pointer space */
- }
- else /* remove a block from free list */
- {
- *ptr = Free;
- Free = Free->Prevline;
- }
- #else /* new way */
- int limbo_index = Limbo - Buf; /* use indices instead of pointers */
- /* N.B.: this statement is meaningless if Limbo == NOMORE */
- /* but if so, we don't use limbo_index anyway */
-
- if (Limbo == NOMORE)
- if (Lastln < (MAXBUF - 1) - 1) /* dumb zero based indexing! */
- *ptr = &Buf[Lastln + 1];
- else
- *ptr = NOMORE;
- else if (limbo_index - Lastln > 1)
- *ptr = &Buf[Lastln + 1];
- else
- *ptr = NOMORE;
- #endif
-
- return (*ptr);
- }
-
-
- /* bump --- advance line number and corresponding index simultaneously */
-
- bump (line, ix, way)
- int *line, way;
- LINEDESC **ix;
- {
- if (way == FORWARD) /* increment line number */
- {
- #ifdef OLD_SCRATCH
- *ix = (*ix)->Nextline;
- if (*ix == Line0)
- *line = 0;
- else
- (*line)++;
- #else
- (*ix)++;
- if (*ix == &Buf[Lastln+1])
- {
- *line = 0;
- *ix = Line0;
- }
- else
- (*line)++;
- #endif
- }
- else /* decrement line number */
- {
- if (*ix == Line0)
- *line = Lastln;
- else
- (*line)--;
- #ifdef OLD_SCRATCH
- *ix = (*ix)->Prevline;
- #else
- if (*ix == Line0)
- *ix = &Buf[Lastln];
- else
- (*ix)--;
- #endif
- }
- }
-
-
-
- /* closef --- close a file */
-
- static closef (fd)
- filedes fd;
- {
- close (fd);
- }
-
-
-
-
- /* clrbuf --- purge scratch file */
-
- clrbuf ()
- {
-
- if (Lastln > 0)
- svdel (1, Lastln);
-
- closef (Scr);
- unlink (Scrname);
- }
-
-
-
- /* garbage_collect --- compress scratch file */
-
- garbage_collect ()
- {
- char new_name [MAXLINE];
- register int i, new_scrend;
- int new_fd;
- register LINEDESC *p;
-
- makscr (&new_fd, new_name);
- remark ("collecting garbage");
- new_scrend = 0;
- #ifdef OLD_SCRATCH
- for (p = Limbo, i = 1; i <= Limcnt; p = p->Nextline, i++)
- #else
- for (p = Limbo, i = 1; i <= Limcnt; p++, i++)
- #endif
- {
- gtxt (p);
- seekf ((long) new_scrend * 8, new_fd);
- writef (Txt, (int) p->Lineleng, new_fd);
- p->Seekaddr = new_scrend;
- new_scrend += (p->Lineleng + 7) / 8;
- }
- #ifdef OLD_SCRATCH
- for (p = Line0, i = 0; i <= Lastln; p = p->Nextline, i++)
- #else
- for (p = Line0, i = 0; i <= Lastln; p++, i++)
- #endif
- {
- gtxt (p);
- seekf ((long) new_scrend * 8, new_fd);
- writef (Txt, (int) p->Lineleng, new_fd);
- p->Seekaddr = new_scrend;
- new_scrend += (p->Lineleng + 7) / 8;
- }
-
- closef (Scr);
- unlink (Scrname);
-
- Scr = new_fd;
- sprintf (Scrname, "%s", new_name);
- Scrend = new_scrend;
- Lost_lines = 0;
-
- remark ("");
- }
-
-
-
- /* gettxt --- locate text for line, copy to txt */
-
- LINEDESC *gettxt (line)
- int line;
- {
- register LINEDESC *k;
- LINEDESC *getind ();
-
- k = getind (line);
- gtxt (k);
-
- return (k);
- }
-
-
-
- /* gtxt --- retrieve a line from the scratch file */
-
- gtxt (ptr)
- register LINEDESC *ptr;
- {
- int readf ();
-
- seekf ((long) ptr->Seekaddr * 8, Scr); /* position to start of file */
- /*
- * rounded Seekaddr to 8 byte sections, giving larger
- * buffer space for text (*8)
- */
-
- return (readf (Txt, (int) ptr->Lineleng, Scr) - 1);
- }
-
-
-
- /* inject --- insert a new line after curln */
-
- inject (lin)
- register char lin [];
- {
- register int i;
- int maklin ();
- register LINEDESC *k1, *k2;
- LINEDESC *k3;
- LINEDESC *getind ();
-
- for (i = 0; lin [i] != EOS; )
- {
- i = maklin (lin, i, &k3); /* create a single line */
- if (i == ERR)
- {
- Errcode = ECANTINJECT;
- return (ERR);
- }
- #ifdef OLD_SCRATCH
- k1 = getind (Curln); /* get pointer to curln */
- k2 = k1-> Nextline; /* get pointer to nextln */
- relink (k1, k3, k3, k2); /* set pointers of new line */
- relink (k3, k2, k1, k3); /* set pointers of prev, next */
- svins (Curln, 1);
- Lastln++; /* update Lastln */
- #else
- Lastln++; /* update Lastln */
- blkmove (Lastln, Lastln, Curln);
- svins (Curln, 1);
- #endif
- Curln++; /* update Curln */
- }
- return (OK);
- }
-
-
-
- /* maklin --- construct a new line, add to scratch file */
-
- maklin (lin, i, newind)
- register char lin [];
- register int i;
- LINEDESC **newind;
- {
-
- char text [MAXLINE];
- register int l, n;
- LINEDESC *ptr;
- LINEDESC *alloc ();
-
- if (alloc (&ptr) == NOMORE) /* get space for pointer block */
- return (ERR);
-
- for (n = i; lin [n] != EOS; n++) /* find end of line */
- if (lin [n] == '\n')
- {
- n++;
- break;
- }
-
- if (n - i >= MAXLINE ) /* can't handle more than MAXLINE chars/line */
- n = i + MAXLINE - 1;
- l = n - i + 1; /* length of new line (including EOS) */
-
- move_ (&lin [i], text, l); /* move new line into text */
- text [l - 1] = EOS; /* add EOS */
-
- ptr->Seekaddr = Scrend; /* will be added to end of scratch file */
- ptr->Lineleng = l; /* line length including EOS */
- ptr->Globmark = NO; /* not marked for Global command */
- ptr->Markname = DEFAULTNAME; /* give it default mark name */
-
- seekf ((long) Scrend * 8, Scr); /* go to end of scratch file */
- writef (text, l, Scr); /* write line on scratch file */
- Scrend += (l + 7) / 8; /* update end-of-file pointer */
-
- Buffer_changed = YES;
-
- *newind = ptr; /* return index of new line */
- return (n); /* return next char of interest in lin */
- }
-
-
-
- /* makscr --- create a new scratch file */
-
- makscr (fd, str)
- register filedes *fd;
- register char str[];
- {
- register int i;
-
- for (i = 0; i <= 9; i++)
- {
- sprintf (str, "/usr/tmp/se%d.%d", getpid(), i);
- /* create str name in /usr/tmp */
- if ((*fd = open (str, 0)) < 0)
- {
- /* if the file is not there, close it and create it */
- close (*fd);
- if ((*fd = creat (str, 0700)) > 0)
- {
- close (*fd);
- if ((*fd = open (str, 2)) > 0)
- return;
- }
- }
- else
- close (*fd);
-
- }
- error ("can't create scratch file");
- }
-
-
-
- /* nextln --- get line after "line" */
-
- nextln (line)
- int line;
- {
- register int ret;
-
- ret = line + 1;
- if (ret > Lastln)
- ret = 0;
-
- return (ret);
- }
-
-
-
- /* prevln --- get line before "line" */
-
- prevln (line)
- int line;
- {
- register int ret;
-
- ret = line - 1;
- if (ret < 0)
- ret = Lastln;
-
- return (ret);
- }
-
-
-
- /* readf --- read count words from fd into buf */
-
- readf (buf, count, fd)
- char buf [];
- int count, fd;
- {
- register int ret;
-
- ret = read (fd, buf, count);
- if (ret != count)
- error ("Fatal scratch file read error");
-
- return (ret);
- }
-
-
- #ifdef OLD_SCRATCH
- /* relink --- rewrite two half links */
-
- relink (a, x, y, b)
- LINEDESC *a, *b, *x, *y;
- {
- x->Prevline = a;
- y->Nextline = b;
- }
- #endif
-
-
-
- /* seekf --- position file open on fd to pos */
-
- static seekf (pos, fd)
- long pos;
- filedes fd;
- {
- register long ret;
- long lseek ();
-
- ret = lseek (fd, pos, 0); /* abs seek */
- if (ret != pos)
- error ("Fatal scratch file seek error");
- return (OK);
- }
-
-
-
- /* mkbuf --- create scratch file, initialize line 0 */
-
- mkbuf ()
- {
- LINEDESC *p;
-
- makscr (&Scr, Scrname); /* create a scratch file */
- Scrend = 0; /* initially empty */
-
- Curln = 0;
- #ifdef OLD_SCRATCH
- Lastln = 0;
- #else
- Lastln = -1; /* alloc depends on this... */
- #endif
-
- #ifdef OLD_SCRATCH
- Lastbf = &Buf[0]; /* next word available for allocation ?? */
- Free = NOMORE; /* free list initially empty */
- #endif
- Limbo = NOMORE; /* no lines in limbo */
- Limcnt = 0;
- Lost_lines = 0; /* no garbage in scratch file yet */
-
- maklin ("", 0, &p); /* create an empty line */
- #ifdef OLD_SCRATCH
- relink (p, p, p, p); /* establish initial linked list */
- #endif
- p->Markname = EOS; /* give it an illegal mark name */
- Line0 = p; /* henceforth and forevermore */
-
- #ifndef OLD_SCRATCH
- Lastln = 0;
- #endif
- }
-
-
-
- /* sp_inject --- special inject for reading files */
-
- LINEDESC *sp_inject (lin, len, line)
- char lin[];
- int len;
- LINEDESC *line;
- {
- register LINEDESC *k, *ret;
- LINEDESC *ptr;
- LINEDESC *alloc ();
-
- ret = alloc (&ptr);
- if (ptr == NOMORE)
- {
- Errcode = ECANTINJECT;
- return (ret);
- }
-
- ptr->Seekaddr = Scrend;
- ptr->Lineleng = len + 1;
- ptr->Globmark = NO;
- ptr->Markname = DEFAULTNAME;
-
- seekf ((long) Scrend * 8, Scr);
- writef (lin, len + 1, Scr);
- Scrend += ((len + 1) + 7) / 8; /* fudge for larger buffer */
- Lastln++;
-
- Buffer_changed = YES;
-
- #ifdef OLD_SCRATCH
- k = line->Nextline;
- relink (line, ptr, ptr, k);
- relink (ptr, k, line, ptr);
- #else
- /*
- * this part dependant on the fact that we set
- * Curln = line in the routine do_read.
- */
- blkmove (ptr - Buf, ptr - Buf, Curln); /* need line no's */
- Curln++;
- #endif
-
- return (ret);
- }
-
-
-
- /* writef --- write count words from buf onto fd */
-
- writef (buf, count, fd)
- char buf[];
- int count;
- filedes fd;
- {
- register int ret;
-
- ret = write (fd, buf, count);
- if (ret != count)
- error ("Fatal scratch file write error");
- return (ret);
- }
-
-
-
- /* getind --- locate line index in buffer */
-
- LINEDESC *getind (line)
- register int line;
- {
- #ifdef OLD_SCRATCH
- register LINEDESC *k;
-
- k = Line0;
- line++;
- while (--line)
- k = k->Nextline;
-
- return (k);
- #else
- return (&Buf[line]);
- #endif
- }
-
- #ifndef OLD_SCRATCH
-
- /* blkmove -- use SWT in Pascal line handling */
-
- blkmove (n1, n2, n3) /* move block of lines n1..n2 to after n3 */
- int n1, n2, n3;
- {
- if (n3 < n1 -1)
- {
- reverse (n3 + 1, n1 - 1);
- reverse (n1, n2);
- reverse (n3 + 1, n2);
- }
- else if (n3 > n2)
- {
- reverse (n1, n2);
- reverse (n2 + 1, n3);
- reverse (n1, n3);
- }
- }
-
- /* reverse -- reverse buf[n1]..buf[n2] */
-
- reverse (n1, n2)
- register int n1, n2;
- {
- LINEDESC temp;
-
- while (n1 < n2)
- {
- temp = Buf[n1];
- Buf[n1] = Buf[n2];
- Buf[n2] = temp;
- n1++;
- n2--;
- }
- }
- #endif
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
-
-